using System.Security.Claims;
using Identity.Infrastructure.Entities;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using OpenIddict.Server.AspNetCore;
using static OpenIddict.Abstractions.OpenIddictConstants;

namespace Identity.HttpAPI.Host.Extensions
{
    public class AddRolesAndPermissionsHandler
    : IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly RoleManager<ApplicationRole> _roleManager;
        private readonly ApplicationDbContext _db;

        public AddRolesAndPermissionsHandler(
            UserManager<ApplicationUser> userManager,
            RoleManager<ApplicationRole> roleManager,
            ApplicationDbContext db)
        {
            _userManager = userManager;
            _roleManager = roleManager;
            _db = db;
        }

        public async ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignInContext context)
        {



            var principal = context.Principal;
            if (principal == null) return;

            var subject = principal.GetClaim(Claims.Subject);
            if (!Guid.TryParse(subject, out var userId)) return;

            var user = await _userManager.FindByIdAsync(userId.ToString());
            if (user == null) return;

            var identity = principal.Identity as ClaimsIdentity
                ?? new ClaimsIdentity(principal.Claims, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
           
            var roles = await _userManager.GetRolesAsync(user);
            foreach (var roleName in roles)
            {
                identity.AddClaim(new Claim(Claims.Role, roleName)
                        .SetDestinations(Destinations.AccessToken,
                   Destinations.IdentityToken));

                //identity.AddClaim(CreateClaim(Claims.Role, roleName,
                //   Destinations.AccessToken));


                var role = await _roleManager.FindByNameAsync(roleName);
                if (role != null)
                {
                    var permIds = await _db.RolePermissions
                        .Where(rp => rp.RoleId == role.Id)
                        .Select(rp => rp.Permission.Name)
                        .ToListAsync();

                    foreach (var p in permIds)
                    {
                        identity.AddClaim(CreateClaim("permission", p, Destinations.AccessToken));
                    }

                }
            }
           
        }

        private static Claim CreateClaim(string type, string value, params string[] destinations)
        {
            var claim = new Claim(type, value);
            claim.SetDestinations(destinations);
            return claim;
        }

    }

}